//
// Created by 郝羽 on 2017/12/13.
//

#ifndef RTC_XSWITCH2_PACKET_HIST_HPP
#define RTC_XSWITCH2_PACKET_HIST_HPP

#include <functional>

namespace bwe {

class PacketInfo {
public:
    PacketInfo() {};

    PacketInfo(uint16_t seq, uint16_t bytes, uint32_t rtp_ts) : seq(seq), bytes(bytes), rtp_ts(rtp_ts) {}

    uint16_t seq;
    uint16_t bytes;
    uint32_t rtp_ts;
};

template<size_t MaxPackets>
class PacketHistory {
    //static constexpr size_t MaxPackets = 128;
public:
    PacketHistory() {};

    void insert_packet(const PacketInfo &p) {
        if (_is_empty) {
            _last = 0;
            _packets[0] = p;
            _is_empty = false;
            return;
        }

        uint16_t last_seq = _packets[_last].seq;
        // uint16_t first_seq = last_seq - MaxPackets + 1;
        uint16_t d1 = p.seq - last_seq;
        uint16_t d2 = last_seq - p.seq;

        if (d1 < 3000) {
            _last += d1;
            _last %= MaxPackets;
            _packets[_last] = p;
        } else if (d2 < MaxPackets) {
            int pos = (_last - d2);
            if (pos < 0) {
                pos += MaxPackets;
            }
            PacketInfo &packet = _packets[pos];
            if (packet.seq == p.seq) {
                return;
            }
            _packets[pos] = p;
        }
    };

    bool get(PacketInfo &p, uint16_t seq) {
        if (_is_empty) {
            return false;
        }
        uint16_t last_seq = _packets[_last].seq;

        uint16_t d2 = last_seq - seq;
        if (d2 >= MaxPackets) {
            return false;
        }
        int pos = _last - d2;
        if (pos < 0) {
            pos += MaxPackets;
        }

        PacketInfo &packet = _packets[pos];
        if (packet.seq != seq) {
            return false;
        }

        p = packet;
        return true;
    }

    void for_each(std::function<void(const PacketInfo &info, bool is_last)> func) {
        if (_is_empty) {
            return;
        }
        int pos = _last - MaxPackets + 1;
        if (pos < 0) {
            pos += MaxPackets;
        }
        uint16_t seq = _packets[_last].seq - MaxPackets + 1;
        while (true) {
            PacketInfo &info = _packets[pos];
            if (info.seq == seq++) {
                func(info, pos == _last);
            }
            if (pos == _last) {
                break;
            }
            ++pos;
            pos %= MaxPackets;
        }
    };

    void reset() {
        memset(_packets, 0, sizeof(_packets) / sizeof(PacketInfo));
        _last = 0;
        _is_empty = true;
    };

private:
    bool _is_empty = true;
    PacketInfo _packets[MaxPackets];
    int _last;
};

} // bwe
#endif //RTC_XSWITCH2_PACKET_HIST_HPP
